/*
** Copyright (C) 2011 Viens Yann
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <cstring>
#include "Variables.hpp"
#include "ObjectDetector.hpp"

ObjectDetector::ObjectDetector(): _cascade(NULL)
{
  loadDetector(detectorPath);
}

ObjectDetector::~ObjectDetector()
{
  if (_cascade)
    {
      delete _cascade;
    }
}

void		ObjectDetector::loadDetector(std::string const& path) throw (InvalidDectectorPath)
{
  if ((_cascade = static_cast<CvHaarClassifierCascade*>(cvLoad(path.data(), 0, 0, 0))) == NULL)
    {
      throw InvalidDectectorPath(path);
    }
}

CvRect*			ObjectDetector::detect(const IplImage *input)
{
  if (_cascade)
    {
      IplImage*		smallImage;
      CvMemStorage*	storage;
      CvSeq*		faces;
      int		c , index;
      CvRect*		rect;
      static CvRect*	final = new CvRect;

      storage = cvCreateMemStorage(0);
      smallImage = cvCreateImage(cvSize(input->width / 2, input->height / 2), IPL_DEPTH_8U, 3);
      cvPyrDown(input, smallImage, CV_GAUSSIAN_5x5);
      faces = cvHaarDetectObjects(smallImage, _cascade, storage, 1.1, 1, CV_HAAR_DO_CANNY_PRUNING, cvSize(0, 0));
      rect = new CvRect[faces->total];
      for (c = 0; c < faces->total; c++)
	rect[c] = *(reinterpret_cast<CvRect*>(cvGetSeqElem(faces, c)));
      index = getBigestWidthRect(rect, faces->total);
      cvReleaseImage(&smallImage);
      cvReleaseMemStorage(&storage);
      if (index == -1)
	{
	  delete [] rect;
	  return (NULL);
	}
      final->x = rect->x * 2;
      final->y = rect->y * 2;
      final->width = rect->width * 2;
      final->height = rect->height * 2;
      delete [] rect;
      return (final);
    }
  return NULL;
}

int	ObjectDetector::getBigestWidthRect(const CvRect *rect, const int nbElem)
{
  int	c = 0, width = -1, index = -1;

  while (c < nbElem)
    {
      if (rect[c].width > width)
	{
	  index = c;
	  width = rect[c].width;
	}
      c++;
    }
  return (index);
}
